package net.jsoft.platform.core.util.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HttpUtils
{
    private static final Logger logger = LogManager.getLogger();

    private static final String GET = "GET";
    //    private static final String POST = "POST";
    private static final String CHARSET = "UTF-8";

    private HttpUtils()
    {
    }

    /**
     * https 域名校验
     */
    private class TrustAnyHostnameVerifier implements HostnameVerifier
    {
        public boolean verify(String hostname, SSLSession session)
        {
            return true;
        }
    }

    /**
     * https 证书管理
     */
    private class TrustAnyTrustManager implements X509TrustManager
    {
        public X509Certificate[] getAcceptedIssuers()
        {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }
    }

    private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();
    private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpUtils().new TrustAnyHostnameVerifier();

    private static SSLSocketFactory initSSLSocketFactory()
    {
        try
        {
            TrustManager[] tm =
            { new HttpUtils().new TrustAnyTrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            return sslContext.getSocketFactory();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers)
            throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException
    {
        logger.debug("getHttpConnection url=[" + url + "], method=[" + method + "], header=[" + headers + "]");
        URL _url = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
        if (conn instanceof HttpsURLConnection)
        {
            ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
            ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier);
        }

        conn.setRequestMethod(method);
        conn.setDoOutput(true);
        conn.setDoInput(true);

        conn.setConnectTimeout(19000);
        conn.setReadTimeout(19000);

        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");

        if (headers != null && !headers.isEmpty())
            for (Entry<String, String> entry : headers.entrySet())
                conn.setRequestProperty(entry.getKey(), entry.getValue());

        return conn;
    }

    /**
     * 发送 get 请求
     */
    public static String get(String url, Map<String, String> queryParas, Map<String, String> headers)
    {
        HttpURLConnection conn = null;
        try
        {
            conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), GET, headers);
            conn.connect();
            return readResponseString(conn);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            if (conn != null)
            {
                conn.disconnect();
            }
        }
    }

    public static String get(String url, Map<String, String> queryParas)
    {
        return get(url, queryParas, null);
    }

    public static String get(String url)
    {
        return get(url, null, null);
    }

    /**
     * 发送 POST 请求 考虑添加一个参数 Map<String, String> queryParas：
     * getHttpConnection(buildUrl(url, queryParas), POST, headers);
     */
    @SuppressWarnings(
    { "rawtypes", "unchecked" })
    public static String post(String url, Map<String, String> queryParas, String charset, Map<String, String> headers)
    {
        //        HttpURLConnection conn = null;
        //        try
        //        {
        //            conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), POST, headers);
        //            conn.connect();
        //
        //            OutputStream out = conn.getOutputStream();
        //            out.write(data.getBytes(CHARSET));
        //            logger.debug("post write data:{" + data + "}");
        //            out.flush();
        //            out.close();
        //
        //            return readResponseString(conn);
        //        } catch (Exception e)
        //        {
        //            throw new RuntimeException(e);
        //        } finally
        //        {
        //            if (conn != null)
        //            {
        //                conn.disconnect();
        //            }
        //        }
        HttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try
        {
            httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            //设置参数  
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            Iterator iterator = queryParas.entrySet().iterator();
            while (iterator.hasNext())
            {
                Entry<String, String> elem = (Entry<String, String>) iterator.next();
                list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
            }
            if (list.size() > 0)
            {
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);
                httpPost.setEntity(entity);
            }
            HttpResponse response = httpClient.execute(httpPost);
            if (response != null)
            {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null)
                {
                    result = EntityUtils.toString(resEntity, charset);
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return result;
    }

    public static String post(String url, Map<String, String> queryParas, String data)
    {
        return post(url, queryParas, data, null);
    }

    public static String post(String url, String data, Map<String, String> headers)
    {
        return post(url, null, data, headers);
    }

    public static String post(String url, String data)
    {
        return post(url, null, data, null);
    }

    private static String readResponseString(HttpURLConnection conn)
    {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try
        {
            inputStream = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET));
            String line = null;
            while ((line = reader.readLine()) != null)
            {
                sb.append(line).append("\n");
            }
            logger.debug("readResponseString resStr=" + sb + "");
            return sb.toString();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            if (null != inputStream)
            {
                try
                {
                    inputStream.close();
                }
                catch (IOException e)
                {
                    inputStream = null;
                    throw new RuntimeException(e);
                }
            }
            if (null != reader)
            {
                try
                {
                    reader.close();
                }
                catch (IOException e)
                {
                    reader = null;
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 在 url 之后构造 queryString
     */
    private static String buildUrlWithQueryString(String url, Map<String, String> queryParas)
    {
        if (queryParas == null || queryParas.isEmpty())
            return url;

        StringBuilder sb = new StringBuilder(url);
        boolean isFirst;
        if (url.indexOf("?") == -1)
        {
            isFirst = true;
            sb.append("?");
        }
        else
        {
            isFirst = false;
        }

        for (Entry<String, String> entry : queryParas.entrySet())
        {
            if (isFirst)
                isFirst = false;
            else
                sb.append("&");

            String key = entry.getKey();
            String value = entry.getValue();
            if (StringUtils.isNotBlank(value))
                try
                {
                    value = URLEncoder.encode(value, CHARSET);
                }
                catch (UnsupportedEncodingException e)
                {
                    throw new RuntimeException(e);
                }
            sb.append(key).append("=").append(value);
        }
        return sb.toString();
    }

    public static String readIncommingRequestData(HttpServletRequest request)
    {
        BufferedReader br = null;
        try
        {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line = null; (line = br.readLine()) != null;)
            {
                result.append(line).append("\n");
            }
            return result.toString();
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            IOUtils.closeQuietly(br);
        }
    }

    /**
     * 发送http GET请求取得返回的输入流
     * 
     * @param requestUrl
     *            请求地址
     * @return InputStream
     */
    public static InputStream httpRequest(String requestUrl)
    {
        InputStream inputStream = null;
        try
        {
            URL url = new URL(requestUrl);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
            httpUrlConn.setDoInput(true);
            httpUrlConn.setRequestMethod(GET);
            httpUrlConn.connect();
            // 获得返回的输入流
            inputStream = httpUrlConn.getInputStream();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
        return inputStream;
    }

}
